package practica3;

import java.util.ArrayList;
import java.util.Random;

import weka.classifiers.Evaluation;
import weka.classifiers.bayes.BayesNet;
import weka.classifiers.bayes.net.search.global.K2;
import weka.core.Instances;

/**Clase que entrena el clasificador BayesNet según 5-fold CV */
public class ScanParamsAlgorithm {
	
	private Evaluation bestEvaluator = null;
	
	public ScanParamsAlgorithm(){}
	
	/**
	 * Metodo que entrena el BayesNet, lo evalua segun 5-fold CV y en base a la f-measure promedio
	 * determina cual es el mejor valor de P (numero de padres) y N (Red inicial vacia o NaiveBaqyes)
	 * @param data Instancias de las que se realizara la clasificacion
	 * @return los mejores valores encontrados para P y N
	 * @throws Exception si el clasificador no puede generarse correctamente o la clase no esta definida
	 */
	public ArrayList<Integer> classify(Instances data) throws Exception{
		int bestP = -1, bestN = -1;
		double fmeasure = -1, fmeasureMax = -1;
		String desc = "", bestDesc = "";
		ArrayList<Integer> bestBN = new ArrayList<Integer>();
		K2 sa = new K2(); //Algoritmo de búsqueda
		BayesNet estimator = new BayesNet();
		
			
		for(int p = 1; p<data.numAttributes(); p++){
			
			sa.setMaxNrOfParents(p); //Número de padres
			for(int n = 0; n<=1; n++){			 	
				if(n==0){
					sa.setInitAsNaiveBayes(false);//Red inicial vacia
					desc = "Vacia";
				}else{ 
					sa.setInitAsNaiveBayes(true);//Red inicial NaiveBayes
					desc = "Naive Bayes";
				}
				
				estimator.setSearchAlgorithm(sa);
				Evaluation evaluator = new Evaluation(data);
				evaluator.crossValidateModel(estimator, data, 5, new Random(45)); 
				
				fmeasure = evaluator.weightedFMeasure();
			
				if(fmeasure>fmeasureMax){
					bestP = p;
					bestDesc = desc;
					fmeasureMax = fmeasure;
					this.bestEvaluator = evaluator; 
				}
			}
		}
		bestBN.add(bestP);
		bestBN.add(bestN);
		
		this.print(bestP, bestDesc);
		
		return bestBN;
		
	}
	/**
	 * Metodo que imprime los resultados del barrido de parametros realizado por el clasificador.
	 * @param bestP  numero de atributos minimo
	 * @param desc valor de la red inicial.
	 */
	private void print(int bestP, String desc) throws Exception{
		System.out.println("\n------------------------------------------");
		System.out.println("RESULTADOS PARA EL ALGORITMO BAYES NETWORK");
		System.out.println("------------------------------------------\n");
		System.out.println("CALIDAD ESPERADA");
		System.out.println("----------------");
		System.out.println("Mejor valor de p (numero de atributos minimo) = " + bestP +"\n");
		System.out.println("Con una red inicial = "+ desc);
		System.out.println(this.bestEvaluator.toSummaryString());
		System.out.println(this.bestEvaluator.toClassDetailsString());
		System.out.println(this.bestEvaluator.toMatrixString());

	}
	
	/**
	 * Metodo para acceder al mejor evaluador
	 * @return devuelve el mejor evaluador
	 */
	public Evaluation getEvaluador(){
		return this.bestEvaluator;
	}
}


